package com.stylefeng.guns.modular.system.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.date.DateTime;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.stylefeng.guns.core.base.controller.BaseController;
import com.stylefeng.guns.core.cache.CacheKit;
import com.stylefeng.guns.core.common.Tools.Result;
import com.stylefeng.guns.core.common.annotion.BussinessLog;
import com.stylefeng.guns.core.common.constant.cache.Cache;
import com.stylefeng.guns.core.common.constant.dictmap.RoleDict;
import com.stylefeng.guns.core.common.constant.state.SpType;
import com.stylefeng.guns.core.common.exception.BizExceptionEnum;
import com.stylefeng.guns.core.exception.GunsException;
import com.stylefeng.guns.core.log.LogObjectHolder;
import com.stylefeng.guns.core.model.SysFunTree;
import com.stylefeng.guns.core.shiro.ShiroUser;
import com.stylefeng.guns.core.util.ToolUtil;
import com.stylefeng.guns.modular.system.model.*;
import com.stylefeng.guns.modular.system.service.*;
import com.stylefeng.guns.modular.system.warpper.RoleCwWarpper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.collections.FastArrayList;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.dao.DataAccessException;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.inject.Inject;
import javax.validation.Valid;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 系统角色(成为)控制器
 *
 * @author fengshuonan
 * @Date 2018-08-30 17:29:48
 */
@Controller
@RequestMapping(value = {"/gunsApi/auth/roleCw"})
@Api(value="用户系统角色接口类",tags={"用户系统角色接口"})
public class RoleCwController extends BaseController {
    
    private static final String CACHE_STRATEGY = "local";

    private String PREFIX = "/system/roleCw/";
    
    @Autowired
    private IOrgcategoryRoleFunctionService orgcategoryRoleFunctionService;
    
    @Autowired
    private IOrgcategoryFunctionService orgcategoryFunctionService;
    
    @Inject
    private IOrgcategoryRoleService orgcategoryRoleService;
    
    @Autowired
    private IFunctionService functionService;
    
    @Inject
    private ISysPrivilegeService sysPrivilegeService;

    @Autowired
    private IRoleCwService roleCwService;

    @Resource
    private IOrgService orgService;
    
    @Autowired
    private IUserCwService userCwService;
    

    /**
     * 跳转到系统角色(成为)首页
     */
    @RequestMapping("")
    public String index() {
        return PREFIX + "roleCw.html";
    }

    /**
     * 跳转到添加系统角色(成为)
     */
    @RequestMapping("/roleCw_add")
    public String roleCwAdd() {
        return PREFIX + "roleCw_add.html";
    }

    /**
     * 跳转到修改系统角色(成为)
     */
    @RequestMapping("/roleCw_update/{roleCwId}")
    public String roleCwUpdate(@PathVariable Integer roleCwId, Model model) {
        RoleCw roleCw = roleCwService.selectById(roleCwId);
        model.addAttribute("item",roleCw);
        LogObjectHolder.me().set(roleCw);
        return PREFIX + "roleCw_edit.html";
    }

    /**
     * 获取系统角色(成为)列表
     */
    @ApiOperation(value="获取系统角色列表",notes = "获取系统角色列表",httpMethod = "GET")
    @GetMapping(value = "/list")
    @ResponseBody
    public Result list(@RequestParam(value = "roleName",required = false) @ApiParam(name = "roleName", value = "角色名称(模糊查询)") String roleName,
                       @RequestParam(value = "soId",required = false) @ApiParam(name = "soId", value = "机构ID") Integer soId,
                       @RequestParam(value = "srSource",required = false) @ApiParam(name = "srSource", value = "来源(0:手动加入 1:自动导入)")String srSource) {
        Wrapper<RoleCw> wrapper=new EntityWrapper<>();
        List<RoleCw> roleCwList=new FastArrayList();
        Org org=null;
        if(StringUtils.isNotBlank(roleName))
            wrapper.like("sr_name",roleName);
        if(StringUtils.isNotBlank(srSource))
            wrapper.eq("sr_source",srSource);
        if (ToolUtil.isNotEmpty(soId)) {
            wrapper.and().eq("so_id", soId);
            org=this.orgService.selectById(soId);
            if(org!=null&&org.getSoLevel().equals(1)){
                String soCate = org.getSoCate();
                if (StringUtils.isNotEmpty(soCate)) {
                    Map map = new HashMap<>();
                    map.put("soc_id", soCate);
                    List<OrgcategoryRole> list = this.orgcategoryRoleService.selectByMap(map);
                    if (list != null && list.size() > 0) {
                        list.stream().sorted(Comparator.comparing(OrgcategoryRole::getSorId)).forEach(orgRole -> {
                            RoleCw roleCw = new RoleCw();
                            // 两个实体不同属性之间拷贝值
                            CopyOptions cp = new CopyOptions();
                            Map map_ = new LinkedHashMap();
                            map_.put("sorId", "srId");
                            map_.put("sorName", "srName");
                            map_.put("sorSort", "srSort");
                            map_.put("socId", "srcTemId");
                            roleCw.setSrSource("1");
                            cp.setFieldMapping(map_);
                            BeanUtil.copyProperties(orgRole, roleCw, cp);
                            roleCwList.add(roleCw);
                        });
                    }
                }
            }
        }
    
        String accout=this.getShiroUser().getAccount();
        if (StringUtils.isNotEmpty(accout) && !StringUtils.equalsIgnoreCase("admin", accout)) {
            int soId_ = getShiroUser().getSoId();
            if (ToolUtil.isNotEmpty(soId_)) {
                Wrapper<Org> orgWrapper = new EntityWrapper<>();
                orgWrapper.eq("so_id", soId_).or();
                orgWrapper.like("so_pids", "%[" + soId_ + "]%");
                List<Org> list = this.orgService.selectList(orgWrapper);
                if (list != null && list.size() > 0) {
                    List<Integer> soIdList =list.parallelStream().map(Org::getSoId).collect(Collectors.toList());
                    if (soIdList != null && soIdList.size() > 0) {
                        wrapper.and().in("so_id", soIdList);
                    }
                }
            }
        }
        
        wrapper.orderBy(true,"so_id,sr_id,srSort");
        List<RoleCw> list = new ArrayList<RoleCw>();
        String soType=org.getSoType();
        if(StringUtils.isNotBlank(soType)&& StringUtils.equals("1",soType)){
            list=roleCwService.selectList(wrapper);
        }else{//部门 获取直接机构地址
            Integer pid=org.getSoPid();
            BB:
            while(true){
               if(pid!=null){
                    Org porg=this.orgService.selectById(pid);
                    if(porg!=null){
                        if(StringUtils.equals("1",porg.getSoType())){
                            soId=porg.getSoId();
                            break;
                         }else{
                            pid= porg.getSoPid();
                            continue BB;
                        }
                    }
                 }
                 break;
            }

            RoleCw roleCw=new RoleCw();
            if(StringUtils.isNoneEmpty(roleName)) roleCw.setSrName(roleName);
            if(soId!=null) roleCw.setSoId(soId);
            if(StringUtils.isNotBlank(srSource))roleCw.setSrSource(srSource);
            list=roleCwService.selectList(new EntityWrapper<>(roleCw));
        }

        if(!roleCwList.isEmpty())
            list.addAll(roleCwList);
        List<Map<String, Object>> mList=new ArrayList<>();
            for (Object o:list){
                Map map= BeanUtil.beanToMap(o);
                mList.add(map);
        }
        return Result.success(super.warpObject(new RoleCwWarpper(mList)));
    }

    /**
     * 新增系统角色(成为)
     */
    @ApiOperation(value="新增系统角色",notes = "新增系统角色",httpMethod ="POST")
    @PostMapping(value = "/add", consumes= MediaType.APPLICATION_JSON_UTF8_VALUE, produces=MediaType.APPLICATION_JSON_UTF8_VALUE)
    @BussinessLog(value = "角色新增")
    @ResponseBody
    @Transactional(rollbackFor = {Exception.class})
    public Result add(@Valid @ApiParam(name = "roleCw", value = "新增角色", required = true)  @RequestBody RoleCw roleCw, BindingResult result) {
        if (result.hasErrors()) {
            throw new GunsException(BizExceptionEnum.REQUEST_NULL);
        }
        String account= this.getShiroUser().getAccount();
        roleCw.setCreateUser(account);
        roleCw.setCreateTime(DateTime.now());
        //验证所属机构和角色是否已存在
        RoleCw old=new RoleCw();
        old.setSrName(roleCw.getSrName());
        old.setSoId(roleCw.getSoId());
        RoleCw theRole = roleCwService.selectOne(new EntityWrapper<>(old));
        if(theRole!=null){
            throw new GunsException(BizExceptionEnum.ROLE_ALREADY_REG);
        }
        //机构分类角色模板ID
        Integer srcTemid=roleCw.getSrcTemId();
        if(ToolUtil.isNotEmpty(srcTemid)){
            Map map=new HashMap();
            map.put("sor_id",srcTemid);
            //获取角色对应的功能菜单
            List<OrgcategoryRoleFunction> list=this.orgcategoryRoleFunctionService.selectByMap(map);
            List<Function> functionList = new FastArrayList();
            
            //获取角色对饮的功能权限
            map.clear();
            map.put("sp_type_id",srcTemid);
            List<OrgcategoryFunction> list1=this.orgcategoryFunctionService.selectByMap(map);
            List<SysPrivilege> privilegeList=new FastArrayList();
            
            if (!list.isEmpty()){
                list.forEach((OrgcategoryRoleFunction function)->{
                    Function f=new Function();
                    BeanUtil.copyProperties(function,f);
                    functionList.add(f);
                });
            }
            
            if(!list1.isEmpty()){
                //两个实体不同属性之间拷贝值
                CopyOptions cp=new CopyOptions();
                Map map1 = new HashMap();
                map1.put("sfId","spFunctionId");
                cp.setFieldMapping(map1);
                list1.forEach((OrgcategoryFunction of)->{
                    SysPrivilege privilege = new SysPrivilege();
                    BeanUtil.copyProperties(of,privilege,cp);
                    privilegeList.add(privilege);
                });
            }
            //插入角色 插入菜单  插入权限
            this.roleCwService.insert(roleCw);
            this.functionService.insertBatch(functionList);
            this.sysPrivilegeService.insertBatch(privilegeList);
        }else{
            this.roleCwService.insert(roleCw);
        }
       
        return Result.success();
    }

    /**
     * 删除系统角色(成为)
     */
    @ApiOperation(value="删除系统角色",notes = "删除系统角色",httpMethod ="DELETE")
    @RequestMapping(value = "/delete",method=RequestMethod.DELETE,produces="application/json;charset=utf-8;")
    @ResponseBody
    @CacheEvict(value = CACHE_STRATEGY,key = "'roleCw_'+#roleCwId",allEntries = true)
    public Result delete(@RequestParam(value = "roleCwId") Integer roleCwId) {
        RoleCw roleCw=roleCwService.selectById(roleCwId);
        if(roleCw!=null){
            if(StringUtils.equals("超级管理员",roleCw.getSrName())){
                throw new GunsException(BizExceptionEnum.ROLE_NOT_DEL);
            }
        }
        //缓存被删除的角色名称
        LogObjectHolder.me().set(roleCw.getSrName());
        this.roleCwService.deleteById(roleCwId);
        //删除缓存
        CacheKit.removeAll(Cache.CONSTANT);
        return Result.success();
    }

    /**
     * 修改系统角色(成为)
     */
    @ApiOperation(value="修改系统角色",notes = "修改系统角色",httpMethod ="POST")
    @PostMapping(value = "/update")
    @ResponseBody
    @CachePut(value = CACHE_STRATEGY,key = "'roleCw_'+#roleCw.srId")
   public Result update(@ApiParam(name = "roleCw", value = "修改角色", required = true) @RequestBody RoleCw roleCw) {
        String srId=roleCw.getSrId();
        if(ToolUtil.isNotEmpty(srId)){
            RoleCw old=this.roleCwService.selectById(srId);
            if(old!=null&&StringUtils.equals("超级管理员",roleCw.getSrName())){
                throw new GunsException(BizExceptionEnum.ROLE_NOT_MODIFY);
            }else{
                //机构分类角色模板ID
                Integer srcTemid=roleCw.getSrcTemId();
                if(ToolUtil.isNotEmpty(srcTemid)){
                    Map map=new HashMap();
                    map.put("sor_id",srcTemid);
                    //获取角色对应的功能菜单
                    List<OrgcategoryRoleFunction> list=this.orgcategoryRoleFunctionService.selectByMap(map);
                    List<Function> functionList = new FastArrayList();
        
                    //获取角色对饮的功能权限
                    map.clear();
                    map.put("soc_id",srcTemid);
                    List<OrgcategoryFunction> list1=this.orgcategoryFunctionService.selectByMap(map);
                    List<SysPrivilege> privilegeList=new FastArrayList();
        
                    if (!list.isEmpty()){
                        list.forEach((OrgcategoryRoleFunction function)->{Function f=new Function();BeanUtil.copyProperties(function,f);functionList.add(f); });
                    }
                    if(!list1.isEmpty()){
                        //两个实体不同属性之间拷贝值
                        CopyOptions cp=new CopyOptions();
                        Map map1 = new HashMap();
                        map1.put("sfId","spFunctionId");
                        cp.setFieldMapping(map1);
                        list1.forEach((OrgcategoryFunction of)->{SysPrivilege privilege = new SysPrivilege();BeanUtil.copyProperties(of,privilege,cp);privilegeList.add(privilege);
                        });
                    }
                    //插入角色 插入菜单  插入权限
                    this.functionService.delete(new EntityWrapper<Function>().eq("sf_id",roleCw.getSrId()));
                    this.sysPrivilegeService.delete(new EntityWrapper<SysPrivilege>().eq("sp_type_id",roleCw.getSrId()).and().eq("sp_type",3));
                    if(!functionList.isEmpty())
                        this.functionService.insertBatch(functionList);
                    if(!privilegeList.isEmpty())
                        this.sysPrivilegeService.insertBatch(privilegeList);
                }
            }
        }
        roleCwService.updateById(roleCw);
        return Result.success();
    }
    /**
     * 配置权限(成为)
     */
    @ApiOperation(value="配置权限",notes = "配置权限",httpMethod ="GET")
    @GetMapping("/setAuthority")
    @BussinessLog(value = "配置权限", key = "roleId,ids", dict = RoleDict.class)
    @ResponseBody
    public Result setAuthority(@ApiParam(name = "roleId", value = "角色ID", required = true) @RequestParam(value = "roleId") int roleId,
                            @ApiParam(name = "soId", value = "机构ID", required = true) @RequestParam("soId") int soId,
                            @ApiParam(name = "ids", value = "权限ID集", required = true) @RequestParam("ids") String ids,
                            @ApiParam(name = "spMethod", value = "访问上下文", required = true) @RequestParam("spMethod") String spMethod
                            ) {
        if (ToolUtil.isOneEmpty(roleId,soId,ids,spMethod)) {
            throw new GunsException(BizExceptionEnum.REQUEST_NULL);
        }
        RoleCw role=this.roleCwService.selectById(roleId);
        Org org=this.orgService.selectById(soId);

        if(role==null){
            throw new GunsException(BizExceptionEnum.NO_THIS_ROLE);
        }
        if(org==null){
            throw new GunsException(BizExceptionEnum.NO_THIS_ORG);
        }
        this.roleCwService.setAuthority(roleId,soId,ids,spMethod);
        return Result.success();
    }
    /**
     * 系统角色(成为)详情
     */
    @ApiOperation(value="角色明细",notes = "角色明细",httpMethod ="GET")
    @GetMapping(value = "/detail")
    @ResponseBody
    public Result detail(@ApiParam(name = "roleCwId", value = "角色ID", required = true) @RequestParam("roleCwId") Integer roleCwId) {
        
        RoleCw roleCw = roleCwService.selectById(roleCwId);
        
        if(ToolUtil.isEmpty(roleCw)){
            throw new GunsException(BizExceptionEnum.ROLE_NOT_EXISTED);
        }
        return Result.success(super.warpObject(new RoleCwWarpper(new ArrayList<Map<String, Object>>(){{
            add(BeanUtil.beanToMap(roleCw));
        }})));
    }
    
    /**
     * 获取系统角色功能列表
     */
    @ApiOperation(value="角色功能列表",notes = "角色功能列表",httpMethod ="GET")
    @GetMapping(value = "/functionList")
    @ResponseBody
    public Result functionList(@ApiParam(name = "roleCwId", value = "角色ID", required = true) @RequestParam("roleCwId") Integer roleCwId) {
        
        RoleCw roleCw = roleCwService.selectById(roleCwId);
        
        if(ToolUtil.isEmpty(roleCw)){
            throw new GunsException(BizExceptionEnum.ROLE_NOT_EXISTED);
        }
        
        Wrapper<SysPrivilege> wrapper=new EntityWrapper<>();
        wrapper.eq("sp_type", SpType.ROLE.getCode()).and();
        wrapper.eq("sp_type_id",roleCwId);
        List<SysPrivilege> list = this.sysPrivilegeService.selectList(wrapper);
        List<Integer> idList=new FastArrayList();
        if(!list.isEmpty()){
           idList=list.parallelStream().sorted(Comparator.comparing(SysPrivilege::getSpFunctionId)).map(SysPrivilege::getSpFunctionId).collect(Collectors.toList());
        }
        
        return Result.success(idList);
    }
    
   
    /**
     * 根据机构分类角色查询所拥有的功能和操作
     */
    @ApiOperation(value="机构分类角色查询所拥有的功能和操作",notes = "机构分类角色查询所拥有的功能和操作",httpMethod ="POST")
    @PostMapping(value = "/selectList")
    @ResponseBody
    public Result selectListOrgcategoryRoleFunction(@ApiParam(name = "roleCw", value = "角色实体", required = true) @RequestBody RoleCw roleCw,BindingResult result) throws DataAccessException {
        if (result.hasErrors()) {
            throw new GunsException(BizExceptionEnum.REQUEST_NULL);
        }
        //返回权限树
        List<SysFunTree> listSysFun = new ArrayList<SysFunTree>();
        // 获取机构分类ID
        Integer soId=roleCw.getSoId();
        Org org=this.orgService.selectById(soId);
        String orgcategoryid="";
        if(ToolUtil.isNotEmpty(org))
            orgcategoryid = org.getSoCate();
        
        // 获取当前角色所有功能
        Wrapper<SysPrivilege> wrapper=new EntityWrapper<>();
        wrapper.eq("sp_type", SpType.ROLE.getCode()).and();
        wrapper.eq("sp_type_id",roleCw.getSrId());
        List<SysPrivilege> list = this.sysPrivilegeService.selectList(wrapper);
        List<Integer> idList=new FastArrayList();
        List<Function> listSysCategoryRoleFun=new ArrayList<>();
        if(list!=null&&list.size()>0){
            idList=list.parallelStream().sorted(Comparator.comparing(SysPrivilege::getSpFunctionId)).map(SysPrivilege::getSpFunctionId).collect(Collectors.toList());
            listSysCategoryRoleFun=this.functionService.selectBatchIds(idList);
        }
      
        // 根据机构分类，获取机构功能树
        List<OrgcategoryFunction> listSysCategoryFun = orgcategoryFunctionService.selectListOrgcategoryFunction(orgcategoryid);
        if (listSysCategoryFun != null && listSysCategoryFun.size()>0) {
            for (OrgcategoryFunction tempOrgCateFun:listSysCategoryFun) {
                SysFunTree sysFunTree = new SysFunTree();
                sysFunTree.setChecked("false");
                for(Function roleFunction:listSysCategoryRoleFun){
                    if(roleFunction.getSfId()==tempOrgCateFun.getSpFunctionId().intValue()){
                        sysFunTree.setChecked("true");
                        break;
                    }
                }
                sysFunTree.setId(""+tempOrgCateFun.getSpFunctionId());
                sysFunTree.setPid(tempOrgCateFun.getSpFunctionPid());
                sysFunTree.setName(tempOrgCateFun.getSpFunctionName());
                if(tempOrgCateFun.getSfIsmenu().equals("1")){
                    sysFunTree.setFunType("F");//tree节点表示功能
                }else{
                    sysFunTree.setFunType("M");//tree节点表示功能
                }
                listSysFun.add(sysFunTree);
            }
        }
        listSysCategoryRoleFun.clear();
        listSysCategoryFun.clear();
        return Result.success(listSysFun);
    }


    @Cacheable(value="local",key = "'userCw_'+#result.getId()")
    public  ShiroUser getShiroUser(){
        String token= getHttpServletRequest().getHeader("Authorization").substring(7);
        return CacheKit.get(CACHE_STRATEGY,token);
    }
}
